package com.boot.dog.web.security.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.boot.dog.common.constant.SecurityConst;
import com.boot.dog.common.auth.DogUser;
import com.boot.dog.web.security.util.SecurityResult;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: MaxLv
 * @Date: 2019/12/2
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String header = request.getHeader(SecurityConst.HEADER);
        if (StrUtil.isBlank(header)) {
            header = request.getParameter(SecurityConst.HEADER);
        }
        boolean notValid = StrUtil.isBlank(header) || (!header.startsWith(SecurityConst.TOKEN_SPLIT));
        if (notValid) {
            chain.doFilter(request, response);
            return;
        }
        try {
            UsernamePasswordAuthenticationToken authentication = getAuthentication(header, response);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception e) {
            log.error("JWTAuthenticationFilter doFilterInternal:{}", e);
        }
        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String header, HttpServletResponse response) {

        String username = null;
        String usertype = null;
        List<GrantedAuthority> authorities = new ArrayList<>();
        try {
            Claims claims = Jwts.parser().setSigningKey(SecurityConst.JWT_SIGN_KEY)
                    .parseClaimsJws(header.replace(SecurityConst.TOKEN_SPLIT, "")).getBody();

            username = claims.getSubject();
            usertype = claims.get(SecurityConst.USER_TYPE).toString();
            String authority = claims.get(SecurityConst.AUTHORITIES).toString();

            if (StrUtil.isNotBlank(authority)) {
                JSON.parseArray(authority, String.class).forEach(ga -> authorities.add(new SimpleGrantedAuthority(ga)));
            }
        } catch (ExpiredJwtException e) {
            SecurityResult.unauthorized(response, "登录已失效,请重新登录");
        } catch (Exception e) {
            log.error("JWTAuthenticationFilter getAuthentication:{}", e);
            SecurityResult.fail(response, "系统错误");
        }

        if (StrUtil.isNotBlank(username)) {
            DogUser principal = new DogUser(username, "", usertype, authorities);
            return new UsernamePasswordAuthenticationToken(principal, null, authorities);
        }
        return null;
    }

}
